{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "class PCA:\n",
    "    def __init__(self, n_components):\n",
    "        \"\"\"初始化PCA\"\"\"\n",
    "        assert n_components >= 1, \"n_components must be valid\"\n",
    "        self.n_components = n_components\n",
    "        slef.components_ = None\n",
    "        \n",
    "    def fit(self, X, eta=0.01, n_iters=1e4):\n",
    "        \"\"\"获取数据集的前n个主成分\"\"\"\n",
    "        assert self.n_components <= X.shape[1], \"n_components must not be greater than the feature number of X\"\n",
    "        \n",
    "        def demean(X):\n",
    "            return X - np.mean(X, axis=0)\n",
    "        \n",
    "        def f(w, X):\n",
    "            return np.sum((X.dot(w)**2)) / len(X)\n",
    "\n",
    "        def df(w, X):\n",
    "            return X.T.dot(X.dot(w)) * 2. / len(X)\n",
    "\n",
    "        # 把向量单位化\n",
    "        def direction(w):\n",
    "            return w / np.linalg.norm(w)\n",
    "\n",
    "        def first_component(X, initial_w, eta, n_iters=1e4, epsilon=1e-8):\n",
    "            w = direction(initial_w)\n",
    "            cur_iter = 0\n",
    "            while cur_iter < n_iters:\n",
    "                gradient = df(w, X)\n",
    "                last_w = w\n",
    "                w = w + eta * gradient\n",
    "                w = direction(w)\n",
    "                if(abs(f(w, X)) - abs(f(last_w, X)) < epsilon):\n",
    "                   break\n",
    "                cur_iter += 1\n",
    "            return w\n",
    "\n",
    "        X_pca = demean(X)\n",
    "        self.components_ = np.empty(shape = (self.n_componentscomponents, X.shape[1]))\n",
    "        for i in range(n):\n",
    "            initial_w = np.random.random(X.shape[1])\n",
    "            eta = 0.001\n",
    "            w = first_component(X_pca, initial_w, eta)\n",
    "            self.components_[i, :] = w\n",
    "            X_pca = X_pca - X_pca.dot(w).reshape(-1, 1) * w\n",
    "        return self\n",
    "    \n",
    "    def transform(self, X):\n",
    "        \"\"\"将给定的X，映射到各个主成分分量中\"\"\"\n",
    "        assert X.shape[1] == self.components_.shape[1]\n",
    "\n",
    "    def __repr__(self):\n",
    "        return \"PCA(n_components=%d)\" % self.n_components"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
